/* 
 * Copyright 2011 kOSMik.
 * This file is part of kOSMik.
 * 
 * kOSMik is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * kOSMik is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with kOSMik.  If not, see <http://www.gnu.org/licenses/>.
 *  
 * kOSMik:
 * Open Street Map - Editor.
 * http://code.google.com/p/swp-dv-ws2010-osm-2/
 */

package de.fuberlin.kosmik.gui.view.adapter;

import java.util.ArrayList;
import java.util.Collection;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import de.fuberlin.kosmik.R;
import de.fuberlin.kosmik.data.DataBaseConnector;
import de.fuberlin.kosmik.data.dao.Poi;
import de.fuberlin.kosmik.data.dao.Way;
import de.fuberlin.kosmik.gui.activity.TrackActivity;
import de.fuberlin.kosmik.gui.view.adapter.TrackInfoAdapter.TrackInfoItem;
import de.fuberlin.kosmik.gui.view.adapter.TrackInfoAdapter.ViewHolderHeader;
import de.fuberlin.kosmik.gui.view.adapter.TrackInfoAdapter.ViewHolderTrackItem;
import de.fuberlin.kosmik.log.Constants;

/**
 * TrackInfoAdapter contains all pois, ways and areas of the track.
 * 
 * @author micha
 */
public class TrackInfoAdapter extends
		ListWithHeadersAdapter<TrackInfoItem, ViewHolderHeader, ViewHolderTrackItem> {

	/**
	 * The possible type of an item.
	 * 
	 */
	public static enum ItemType {
		/**
		 * Point of interest.
		 */
		POI,
		/**
		 * Way.
		 */
		WAY,
		/**
		 * Area.
		 */
		AREA
	}

	private TrackActivity context;
	private DataBaseConnector dbConnector;
	private static int nrCounter;
	private String poiHeaderName;
	private String wayHeaderName;
	private String areaHeaderName;
	/**
	 * Id of the current track.
	 */
	long trackId;

	/**
	 * Constructor.
	 * 
	 * @param context of the caller
	 * @param trackId of the current track
	 */
	public TrackInfoAdapter(TrackActivity context, long trackId) {
		super(context, R.layout.track_list_header, R.layout.track_item_list_row);
		this.context = context;
		poiHeaderName = context.getString(R.string.track_info_poi_header);
		areaHeaderName = context.getString(R.string.track_info_are_header);
		wayHeaderName = context.getString(R.string.track_info_way_header);

		nrCounter = 1;
		this.trackId = trackId;
		addTrackItems();
	}

	private void addTrackItems() {
		Log.d(Constants.TAG, "Adapter: addTrackItems() id" + trackId);
		dbConnector = context.getDataBase();
		addPois();
		addWaysAndAreas();
	}

	private void addPois() {
		Collection<Poi> pois = dbConnector.getPoisFromTrack(trackId);
		Log.d(Constants.TAG, "Adapter: pois nr" + pois.size());
		if (pois.size() > 0)
			add(new TrackInfoItem(poiHeaderName));
		TrackInfoItem trackListItem;
		for (Poi poi : pois) {
			trackListItem = new TrackInfoItem(poi.values, poi.poiId, nrCounter++, ItemType.POI);
			add(trackListItem);
		}
	}

	private void addWaysAndAreas() {
		Collection<Way> ways = dbConnector.getWaysByTrack(trackId);

		Log.d(Constants.TAG, ways.toString());
		Collection<Way> areas = new ArrayList<Way>();
		Log.d(Constants.TAG, "Adapter: ways nr" + ways.size());
		TrackInfoItem trackListItem;
		// add ways and remove ways object from collection
		if (ways.size() > 0)
			add(new TrackInfoItem(wayHeaderName));

		for (Way way : ways) {
			Log.d(Constants.TAG, way.tags.toString() + " is Area:" + way.isArea);
			if (!way.isArea) {
				trackListItem = new TrackInfoItem(way.tags, way.wayId, nrCounter++,
						ItemType.WAY);
				add(trackListItem);
			} else {

				areas.add(way);
			}
		}
		// add areas
		Log.d(Constants.TAG, "Adapter: areas nr" + areas.size());
		if (areas.size() > 0)
			add(new TrackInfoItem(areaHeaderName));
		for (Way area : areas) {
			trackListItem = new TrackInfoItem(area.tags, area.wayId, nrCounter++, ItemType.AREA);
			add(trackListItem);
		}

	}

	/**
	 * Contains basic information about a track item.
	 */
	public class TrackInfoItem implements ListItem {
		/**
		 * Id of the current item.
		 */
		public long id;
		/**
		 * The number of the item in the list.
		 */
		int nr;
		/**
		 * Indicates whether the item is a header or a standard item.
		 */
		boolean isHeader;
		/**
		 * Indicates whether the item is a poi, area or way.
		 */
		public ItemType itemType;

		/**
		 * String representation of the item or header.
		 */
		String name;

		/**
		 * Contains all key value pairs (tags) of the item.
		 */
		public Bundle tagsBundle;

		/**
		 * Constructor, should use for ListItems.
		 * 
		 * @param tagsBundle key value pairs of the item
		 * @param id of the item in db
		 * @param nr of the item in the list
		 * @param itemType shows whether the item is a header, poi, or way.
		 */
		TrackInfoItem(Bundle tagsBundle, long id, int nr, ItemType itemType) {
			this.id = id;
			this.tagsBundle = tagsBundle;
			this.nr = nr;
			this.itemType = itemType;
		}

		/**
		 * Constructor, should use for header items.
		 * 
		 * @param headerName the name of the header.
		 */
		TrackInfoItem(String headerName) {
			this.isHeader = true;
			this.name = headerName;
		}

		@Override
		public String toString() {
			if (!isHeader) {
				if (name != null)
					return name;
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.append(" ");
				boolean firstTag = true;
				for (String key : tagsBundle.keySet()) {
					if (firstTag) {
						firstTag = false;
					} else {
						stringBuilder.append(" \n ");
					}
					stringBuilder.append(key);
					stringBuilder.append(" = ");
					stringBuilder.append(tagsBundle.getString(key));

				}
				name = stringBuilder.toString();
				return name;
			}
			// if item is a header return empty string so the header is
			// hiding in case of filtering.
			return "";
		}

		@Override
		public boolean isHeader() {
			return isHeader;
		}
	}

	/**
	 * A ViewHolderClass which contains all Views of a list item to avoid
	 * findViewById() calls.
	 */
	public static class ViewHolderTrackItem implements ViewHolder<TrackInfoItem> {
		/**
		 * Contains all info about the item.
		 */
		public TrackInfoItem trackInfoItem;
		/**
		 * View the nr of the current item.
		 */
		public TextView itemNr;
		/**
		 * View which shows the name of the current track.
		 */
		public TextView itemTags;

		@Override
		public boolean isHeader() {
			return false;
		}

		@Override
		public TrackInfoItem getItem() {
			return trackInfoItem;
		}
	}

	/**
	 * A ViewHolderClass which contains all Views of a list header to avoid
	 * findViewById() calls.
	 */
	public static class ViewHolderHeader implements ViewHolder<TrackInfoItem> {
		/**
		 * View which shows the name of the current header.
		 */
		TextView headerName;

		@Override
		public boolean isHeader() {
			return true;
		}

		@Override
		public TrackInfoItem getItem() {
			return null;
		}
	}

	@Override
	ViewHolderHeader findViewsOfHeader(View convView) {
		ViewHolderHeader headerHolder = new ViewHolderHeader();
		headerHolder.headerName = (TextView) convView.findViewById(R.id.track_list_header_name);
		return headerHolder;
	}

	@Override
	void setViewsOfHeader(ViewHolderHeader headerHolder, TrackInfoItem listItem) {
		headerHolder.headerName.setText(listItem.name);
	}

	@Override
	ViewHolderTrackItem findViewsOfItem(View convView) {
		ViewHolderTrackItem trackHolder = new ViewHolderTrackItem();
		trackHolder.itemTags = (TextView) convView.findViewById(R.id.trackItem);
		trackHolder.itemNr = (TextView) convView.findViewById(R.id.trackItemNr);
		return trackHolder;
	}

	@Override
	void setViewsOfItem(ViewHolderTrackItem trackHolder, TrackInfoItem trackListItem) {
		trackHolder.itemNr.setText(trackListItem.nr + ")");
		trackHolder.itemTags.setText(trackListItem.toString());
		trackHolder.trackInfoItem = trackListItem;
	}

	/**
	 * Refreshes the list of items.
	 */
	public void refreshItems() {
		clear();
		nrCounter = 1;
		addTrackItems();
	}

}
